home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / comm / bbs / s342q07.lha / events.c < prev    next >
C/C++ Source or Header  |  1995-03-06  |  22KB  |  824 lines

  1. /*
  2. *                               events.c
  3. *
  4. * Event handling code for Citadel.
  5. */
  6. #include "ctdl.h"
  7. /* #define EVENT_DEBUG */
  8. /*
  9. *                               history
  10. *
  11. * 91Aug16 HAW  New comment style.
  12. * 89Jan23 HAW  Version 2 of event handling.
  13. * 87Jun13 HAW  Created.
  14. */
  15. /*
  16. *                               contents
  17. *
  18. *      InitEvents()             Initialize event stuff
  19. *      eventSort()              Sorts events
  20. *      setPtrs()                Set up pointers
  21. *      DoTimeouts()             Handles timeouts
  22. */
  23. /*
  24. * Event facility description
  25. *
  26. * Not available.
  27. */
  28. /*
  29. *                               Variables
  30. */
  31. /* Internal housekeeping variables */
  32. static int    ThisDay, ThisMinute;
  33. static long   ThisSecond;
  34. static char   warned = FALSE;
  35. static long   ThisAbsolute;
  36. /* These are lists of events */
  37. typedef struct
  38.   {
  39.   SListBase List;
  40.   long      NextAbs;
  41.   long      LastAbs;
  42.   int       toReturn;
  43.  
  44.   }
  45. EventList;
  46. static EventList Types [] =
  47.   {
  48.     { { NULL, NULL, eventSort, NULL, NULL   }, -1l, -1l, TRUE  },
  49.     { { NULL, NULL, eventSort, NULL, NULL   }, -1l, -1l, FALSE },
  50.     { { NULL, NULL, eventSort, NULL, NULL   }, -1l, -1l, FALSE }
  51.   };
  52. typedef struct
  53.   {
  54.   EVENT *Evt;
  55.   long  finish;
  56.  
  57.   }
  58. EvDoorRec;
  59. static SListBase AutoDoors =
  60.   {
  61.   NULL, ChED, CmpED, free, NULL
  62.  
  63.   };
  64. static SListBase Redirected =
  65.   {
  66.   NULL, ChRed, CmpED, free, NULL
  67.  
  68.   };
  69. int ClassActive[EVENT_CLASS_COUNT];     /* which classes are active? */
  70. #define NewUserAllowed()        (ClassActive[CL_NEWUSERS_ALLOWED])
  71. #define NewUserDisAllowed()     (ClassActive[CL_NEWUSERS_DISALLOWED])
  72. static SListBase EventEnds =
  73.   {
  74.   NULL, ChkTwoNumbers, CmpTwoLong, free, NULL
  75.  
  76.   };
  77. /*
  78. * This list helps solve the 'cheating downloader' problem.  We keep a list
  79. * of downloaders and the amount of time spent downloading.  This list is
  80. * cleared whenever the limit changes; thus, it is only effective during the
  81. * duration of a specific download time limit #event.  We reference the list
  82. * every time a user logs in (see LOG.C).
  83. */
  84. SListBase DL_List =
  85.   {
  86.   NULL, ChkTwoNumbers, CmpTwoLong, free, EatTwoNumbers
  87.  
  88.   };
  89. extern long *DL_Total;
  90. char ResolveDls = TRUE;
  91. char *DlMsgPtr = NULL;
  92. static EVENT *Cur;
  93. /* Externally needed variables */
  94. char   ForceNet = FALSE;        /* True IFF ^A has been pressed         */
  95. long   DeadTime;                /* Useful to keep this as a local       */
  96. long   AnyNetLen;               /* Same here, tonto                     */
  97. MULTI_NET_DATA AnyTimeNets;
  98. long Door_Limit;
  99. extern EVENT  *EventTab;
  100. extern MessageBuffer msgBuf;
  101. extern CONFIG cfg;
  102. extern char   outFlag;
  103. extern char   haveCarrier;
  104. extern char   onConsole;
  105. extern char   whichIO;          /* where is the I/O?            */
  106. extern char   justLostCarrier;
  107. extern char   ExitToMsdos;
  108. extern int    exitValue;
  109. extern long   Dl_Limit;    /* Yuck, but necessary */
  110. void SetAbs(EventList *list, long LastAbs);
  111. /*
  112. * InitEvents()
  113. *
  114. * This function initializes events stuff.  This boils down to placing the
  115. * various events into their types (implemented in SListBase structures), which
  116. * automatically sorts them as they are added based on how close they are to
  117. * the time they are supposed to occur.
  118. */
  119. void InitEvents()
  120.   {
  121.   int      i;
  122.   InitEvTimes();
  123.   zero_array(ClassActive);              /* all classes off for now      */
  124.   for (i = 0; i < cfg.EvNumber; i++)
  125.     {
  126.     if (EventTab[i].EvClass == CLREL)
  127.       {
  128.       EventTab[i].EvMinutes =
  129.       (ThisMinute + EventTab[i].EvDur) % 10080;
  130.  
  131.       }
  132.     AddData(&Types[EventTab[i].EvType].List, EventTab + i, NULL, FALSE);
  133.  
  134.     }
  135.   SetAbs(&Types[0], -1l);
  136.   SetAbs(&Types[1], -1l);
  137.   SetAbs(&Types[2], -1l);
  138.  
  139.   }
  140. /*
  141. * InitEvTimes()
  142. *
  143. * This function initializes various time-based global variables for use by
  144. * the event stuff.
  145. */
  146. void InitEvTimes()
  147.   {
  148.   int      yr, dy, hr, mn, mon, secs, milli;
  149.   long     temp;
  150.   getRawDate(&yr, &mon, &dy, &hr, &mn, &secs, &milli);
  151.   ThisDay = WhatDay();
  152.   ThisMinute = (ThisDay * 1440) + (hr * 60) + mn;
  153.   temp = (long) ThisMinute;
  154.   ThisSecond = (temp * 60l) + secs;
  155.   ThisAbsolute = CurAbsolute();
  156.  
  157.   }
  158. /*
  159. * eventSort()
  160. *
  161. * This helps sort a list of events (a type implementation) based on how soon
  162. * each event is to occur.
  163. */
  164. int eventSort(EVENT *s1, EVENT *s2)
  165.   {
  166.   if (during(s1) && during(s2))  return (int) (s1->EvMinutes - s2->EvMinutes);
  167.   if (during(s1)) return -1;
  168.   if (during(s2)) return 1;
  169.   if ((passed(s1) && passed(s2)) ||
  170.   (!passed(s1) && !passed(s2)))  return (int)(s1->EvMinutes - s2->EvMinutes);
  171.   return (int) (s2->EvMinutes - s1->EvMinutes);
  172.  
  173.   }
  174. /*
  175. * during()
  176. *
  177. * Are we "during" this event?  This question is answered by checking to see
  178. * if this event's time period (beginning to beginning+duration) encompasses
  179. * the current time (within the week period).  The code is slightly more
  180. * complex than might be otherwise expected due to the rollover point at the
  181. * end of a week (Saturday).
  182. */
  183. int during(EVENT *x)
  184.   {
  185.   int result;
  186.   result = FALSE;
  187.   if (ThisMinute >= x->EvMinutes && ThisMinute < x->EvMinutes + x->EvDur)
  188.     {
  189.     result = TRUE;
  190.     }
  191.   else
  192.     {
  193.     if (x->EvMinutes + x->EvDur > 10080
  194.       && ThisMinute < (x->EvMinutes + x->EvDur) % 10080)
  195.       {
  196.       result = TRUE;
  197.       };
  198.     };
  199.   return result;
  200.  
  201.   }
  202. /*
  203. * passed()
  204. *
  205. * This function determines if this event's start time has passed in terms of
  206. * the week.
  207. */
  208. int passed(EVENT *x)
  209.   {
  210.   if ((x->EvDur == 0 && x->EvMinutes <= ThisMinute) ||
  211.   (x->EvDur != 0 && x->EvMinutes < ThisMinute))  return TRUE;
  212.   return FALSE;
  213.  
  214.   }
  215. /*
  216. * SetAbs()
  217. *
  218. * This function calculates when the next event is supposed to occur for the
  219. * given type.  This is calculated in terms of absolute time, making later
  220. * comparisons much easier to deal with.  Since it's possible that this
  221. * function will be called when we're actually already into some event's
  222. * period, we have to take this into account.  That should explain the check
  223. * for during() at the end of the function.
  224. */
  225. void SetAbs(EventList *list, long LowLimit)
  226.   {
  227.   long temp, InSeconds;
  228.   if ((Cur = (EVENT *) GetFirst(&list->List)) != NULL)
  229.     {
  230.     InitEvTimes();
  231.     temp = (long) Cur->EvMinutes;
  232.     InSeconds = temp * 60l;
  233.     if (during(Cur))
  234.     list->NextAbs = ThisAbsolute - WeekDiff(ThisSecond, InSeconds);
  235.     else if (LowLimit != -1l)
  236.       {
  237.       if (ThisAbsolute - WeekDiff(ThisSecond, InSeconds) > LowLimit)
  238.       list->NextAbs = ThisAbsolute - WeekDiff(ThisSecond, InSeconds);
  239.       else
  240.       list->NextAbs = ThisAbsolute + WeekDiff(InSeconds, ThisSecond);
  241.  
  242.       }
  243.     else
  244.     list->NextAbs = ThisAbsolute + WeekDiff(InSeconds, ThisSecond);
  245.  
  246.     }
  247.  
  248.   }
  249. /*
  250. * WeekDiff()
  251. *
  252. * This function figures out difference in time between events, taking into
  253. * account the week rollover stuff.  The difference is returned in seconds.
  254. */
  255. long WeekDiff(long future, long now)
  256.   {
  257.   long diff;
  258.   if( cfg.BoolFlags.debug )
  259.     {
  260.     splitF(NULL,"WeekDiff(future:%ld, now:%ld) =",future, now);
  261.     };
  262.   diff = (long)( ( now > future) ? (604800l - now + future ) : ( future - now) );
  263.   if( cfg.BoolFlags.debug )
  264.     {
  265.     splitF(NULL,"%ld\n",diff);
  266.     };
  267.   return diff;
  268.   }
  269. /*
  270. * ChkPreempt()
  271. *
  272. * This function will estimate whether the time to d/l will interfere with
  273. * the next preemptive event.  If it does, then the warning string associated
  274. * with this preemptive event is returned.  If there is no collision then
  275. * NULL is returned.
  276. */
  277. char *ChkPreempt(long estimated)
  278.   {
  279.   if ((Cur = GetFirst(&Types[0].List)) != NULL)
  280.     {
  281.     if (Types[0].NextAbs - CurAbsolute() < estimated)
  282.     return (char *)(cfg.codeBuf + Cur->EvWarn);
  283.  
  284.     }
  285.   return NULL;          /* No preemptive events to worry about */
  286.  
  287.   }
  288. /*
  289. * CheckAutoDoor()
  290. *
  291. * This function checks to see if the given login name has an autodoor that
  292. * should be executed.  It returns -1 if no such autodoor exists, otherwise
  293. * it returns the EvExitVal value associated with the autodoor entry.  This
  294. * function resides in here rather than the door source because autodoors
  295. * are implemented as #events.
  296. */
  297. int CheckAutoDoor(char *name)
  298.   {
  299.   EvDoorRec rec;
  300.   rec.Evt = GetDynamic(sizeof (EVENT)); /* get around possible bug */
  301.   strCpy(rec.Evt->vars.EvUserName, name);
  302.   if ((Cur = SearchList(&AutoDoors, &rec)) != NULL)
  303.     {
  304.     free(rec.Evt);
  305.     return (int) Cur->EvExitVal;
  306.  
  307.     }
  308.   free(rec.Evt);
  309.   return ERROR;
  310.  
  311.   }
  312. /*
  313. * DoTimeouts()
  314. *
  315. * This is the function responsible for actual checking of timeouts.  It
  316. * returns TRUE if you want modIn to break out, too.  It should only be called
  317. * from modIn().
  318. */
  319. char DoTimeouts()
  320.   {
  321.   int  yr, dy, hr, mn, temp, mon, secs, milli;
  322.   #ifdef SYSTEM_CLOCK
  323.   static int LastMinute = -1;
  324.   #endif
  325.   extern int PriorityMail;
  326.   TwoNumbers *tmp;
  327.   EvDoorRec  *evtmp;
  328.   extern SListBase UntilNetSessions;
  329.   getRawDate(&yr, &mon, &dy, &hr, &mn, &secs, &milli);
  330.   #ifdef SYSTEM_CLOCK
  331.   if (LastMinute != mn || ForceNet )
  332.     {
  333.     ScrTimeUpdate(hr, mn);
  334.     LastMinute = mn;
  335.  
  336.     }
  337.   else
  338.     {
  339.     BeNice(INUSE_PAUSE);  /* check for ARexx input and sleep */
  340.     };
  341.   #endif
  342.   ThisMinute = (WhatDay() * 1440) + (hr * 60) + mn;
  343.   ThisAbsolute = (long) ThisMinute;
  344.   ThisSecond = ThisAbsolute * 60 + secs;
  345.   ThisAbsolute = CurAbsolute();
  346.   /* First we deal with events which are deactivating */
  347.   if ((tmp = GetFirst(&EventEnds)) != NULL)
  348.     {
  349.     if (ThisAbsolute >= tmp->second)
  350.       {
  351.       /* event is ending! */
  352.       ClassActive[tmp->first] = FALSE;
  353.       KillData(&EventEnds, tmp);                /* take it off the list */
  354.       if (tmp->first == CL_DL_TIME)
  355.       ResolveDLStuff();
  356.  
  357.       }
  358.  
  359.     }
  360.   if ((evtmp = GetFirst(&AutoDoors)) != NULL)
  361.     {
  362.     if (ThisAbsolute >= evtmp->finish)
  363.       {
  364.       /* autodoor finish */
  365.       KillData(&AutoDoors, evtmp);
  366.  
  367.       }
  368.  
  369.     }
  370.   if ((evtmp = GetFirst(&Redirected)) != NULL)
  371.     {
  372.     if (ThisAbsolute >= evtmp->finish)
  373.       {
  374.       /* redirection finish */
  375.       KillData(&Redirected, evtmp);
  376.  
  377.       }
  378.  
  379.     }
  380.   /* Next we deal with preemptive events, which are Type 0 */
  381.   /* give a warning at T-5 */
  382.   if ((Cur = GetFirst(&Types[0].List)) != NULL &&
  383.   !warned && Types[0].NextAbs - ThisAbsolute < 300l && onLine())
  384.     {
  385.     temp = Cur->EvMinutes % 1440;
  386.     warned = TRUE;
  387.     outFlag = IMPERVIOUS;
  388.     Output_Citadel_Message("ESYSDN",temp/60,temp%60,(long)Cur->EvWarn+(long)cfg.codeBuf);
  389.     outFlag = OUTOK;
  390.     return (char)FALSE;
  391.  
  392.     }
  393.   else if (Cur != NULL && Types[0].NextAbs < ThisAbsolute)
  394.     {
  395.     if (onLine())
  396.       {
  397.       /* first boot off user, next time do event */
  398.       outFlag = IMPERVIOUS;
  399.       Output_Citadel_Message("EVHAPP",(long)Cur->EvWarn + (long)cfg.codeBuf, NULL, NULL);
  400.       if (onConsole)
  401.         {
  402.         /* Ugly cheat */
  403.         onConsole = FALSE;
  404.         whichIO = MODEM;
  405.         justLostCarrier = TRUE;
  406.         EnableModem(FALSE);
  407.  
  408.         }
  409.       else
  410.       HangUp(FALSE);
  411.       outFlag = OUTOK;
  412.       return (char)TRUE;
  413.  
  414.       }
  415.     return (char)FigureEvent(0);
  416.  
  417.     }
  418.   if (!onLine() && (Cur = GetFirst(&Types[1].List)) != NULL &&
  419.   Types[1].NextAbs < ThisAbsolute)
  420.   return (char)FigureEvent(1);
  421.   if ((Cur = GetFirst(&Types[2].List)) != NULL &&
  422.   Types[2].NextAbs < ThisAbsolute)
  423.   return (char)FigureEvent(2);
  424.   /* check priority mail -- odd place for the check, but wotthehell */
  425.   if (PriorityMail)
  426.     {
  427.     if (!onLine())
  428.       {
  429.       netController((hr*60) + mn, 0, PRIORITY_MAIL, ANYTIME_NET, 0);
  430.       PriorityMail = 0;
  431.  
  432.       }
  433.  
  434.     }
  435.   /* handle anytime netting here - is special type of thing */
  436.   if (chkTimeSince(NEXT_ANYNET) > DeadTime || ForceNet)
  437.     {
  438.     if (ClassActive[CL_ANYTIME_NET])
  439.       {
  440.       if (!onLine())
  441.         {
  442.         netController((hr * 60) + mn, AnyNetLen,
  443.         AnyTimeNets, ANYTIME_NET, 0);
  444.         ScrNewUser();
  445.         ForceNet = FALSE;
  446.  
  447.         }
  448.  
  449.       }
  450.     else ForceNet = FALSE;
  451.     startTimer(NEXT_ANYNET);
  452.  
  453.     }
  454.   /*
  455.   * now see if we have any other net sessions due to be run.  These are
  456.   * sessions scheduled by the user from the Net menu. If so, run each of
  457.   * them by killing the list (the kill function should run each).
  458.   */
  459.   if (!onLine() && GetFirst(&UntilNetSessions) != NULL)
  460.     {
  461.     KillList(&UntilNetSessions);
  462.  
  463.     }
  464.   return (char)ExitToMsdos;
  465.  
  466.   }
  467. /*
  468. * ResolveDLStuff()
  469. *
  470. * Resolves the DL list when a limit changes.  Basically, we clear the list of
  471. * all users, but if someone is currently on, we wish to retain the user's
  472. * record.  So, we make a copy of it, clear the list, and then restore the
  473. * user's record to the list.  This code and related code elsewhere should
  474. * help minimize the 'cheating user' problem.
  475. */
  476. void ResolveDLStuff()
  477.   {
  478.   TwoNumbers  *tmp = NULL;
  479.   extern int  thisLog;  /* entry currently in logBuf    */
  480.   extern char loggedIn;
  481.   if (!ResolveDls)
  482.     {
  483.     ResolveDls = TRUE;
  484.     return;
  485.  
  486.     }
  487.   if (loggedIn)         /* this makes a copy if someone is on */
  488.   tmp = MakeTwo(thisLog, *DL_Total);
  489.   KillList(&DL_List);           /* Now clear the list           */
  490.   if (tmp != NULL)
  491.     {
  492.     /* If someone is on, re-add to the list */
  493.     AddData(&DL_List, tmp, NULL, TRUE);
  494.     DL_Total = &tmp->second;    /* And keep pointing    */
  495.  
  496.     }
  497.  
  498.   }
  499. /*
  500. * FigureEvent()
  501. *
  502. * This function handles an event becoming active and takes action.
  503. */
  504. int FigureEvent(int index)
  505.   {
  506.   long ThisAbs, temp, InSeconds, EndIt = -1l, CalcEnd;
  507.   EvDoorRec *EvDoor;
  508.   temp = (long) Cur->EvMinutes;
  509.   InSeconds = temp * 60l;
  510.   ThisAbs = ThisAbsolute - WeekDiff(ThisSecond, InSeconds);
  511.   CalcEnd = ThisAbs + (Cur->EvDur * 60l);
  512.   switch (Cur->EvClass)
  513.     {
  514.     case CL_UNTIL_NET:
  515.     case CLNET:
  516.     netController(Cur->EvMinutes % 1440, Cur->EvDur, Cur->EvExitVal,
  517.     (Cur->EvClass == CLNET) ? NORMAL_NET : UNTIL_NET,
  518.     REPORT_FAILURE | LEISURELY);
  519.     warned = FALSE;
  520.     startTimer(NEXT_ANYNET);
  521.     break;
  522.     case CLEXTERN:
  523.     case CLREL:
  524.     ExitToMsdos = TRUE;
  525.     exitValue = (int) Cur->EvExitVal;
  526.     return TRUE;        /* force it */
  527.     case CL_DL_TIME:
  528.     EndIt = CalcEnd;
  529.     Dl_Limit = Cur->EvExitVal;
  530.     ResolveDLStuff();
  531.     DlMsgPtr = cfg.codeBuf + Cur->EvWarn;
  532.     break;
  533.     case CL_ANYTIME_NET:
  534.     EndIt = CalcEnd;
  535.     /* gets eligible nets */
  536.     AnyTimeNets = Cur->EvExitVal;
  537.     DeadTime    = Cur->vars.Anytime.EvDeadTime;
  538.     AnyNetLen   = Cur->vars.Anytime.EvAnyDur;
  539.     break;
  540.     case CL_DOOR_TIME:
  541.     EndIt = CalcEnd;
  542.     Door_Limit = Cur->EvExitVal;
  543.     break;
  544.     case CL_AUTODOOR:
  545.     case CL_REDIRECT:
  546.     EvDoor = GetDynamic(sizeof *EvDoor);
  547.     EvDoor->Evt = Cur;
  548.     EvDoor->finish = CalcEnd;
  549.     AddData((Cur->EvClass == CL_AUTODOOR) ? &AutoDoors : &Redirected,
  550.     EvDoor, NULL, TRUE);
  551.     break;
  552.     case CL_CHAT_ON:
  553.     case CL_CHAT_OFF:
  554.     cfg.BoolFlags.noChat = (Cur->EvClass != CL_CHAT_ON);
  555.     ScrNewUser();
  556.     break;
  557.     case CL_NEWUSERS_ALLOWED:
  558.     case CL_NEWUSERS_DISALLOWED:
  559.     cfg.BoolFlags.unlogLoginOk = (Cur->EvClass == CL_NEWUSERS_ALLOWED);
  560.     EndIt = CalcEnd;
  561.     break;
  562.     case CL_NETCACHE:
  563.     CacheMessages(Cur->EvExitVal, FALSE);
  564.     break;
  565.     default:    /* do nothing */
  566.     ;       /* required by ANSI */
  567.  
  568.     }
  569.   if (EndIt != -1l)
  570.     {
  571.     AddData(&EventEnds, MakeTwo(Cur->EvClass, EndIt), NULL, TRUE);
  572.     ClassActive[Cur->EvClass] = TRUE;       /* turn it on, baby! */
  573.  
  574.     }
  575.   FrontToEnd(&Types[index].List);       /* put event on end of list */
  576.   Types[index].LastAbs = ThisAbs;
  577.   SetAbs(&Types[index], Types[index].LastAbs);
  578.   return Types[index].toReturn;
  579.  
  580.   }
  581. /*
  582. * ActiveEvents()
  583. *
  584. * This puts together something vaguely resembling a useful list of currently
  585. * active events.
  586. */
  587. void ActiveEvents(char *buf)
  588.   {
  589.   int i;
  590.   sPrintf(lbyte(buf), "\n   Active Event,s:\n ");
  591.   if (Dl_Limit_On())                sPrintf(lbyte(buf), "D-L time limit of %ld minutes.\n ", Dl_Limit);
  592.   if (Door_Limit_On())              sPrintf(lbyte(buf), "Door time limit of %ld minutes.\n ", Door_Limit);
  593.   if (GetFirst(&Redirected) != NULL)sPrintf(lbyte(buf), "%d Redirect Files active.\n ",  RunList(&Redirected, NoFree));
  594.   if (GetFirst(&AutoDoors) != NULL) sPrintf(lbyte(buf), "%d Auto Doors active.\n ", RunList(&AutoDoors, NoFree));
  595.   if (NewUserAllowed())             sPrintf(lbyte(buf), "New Users Allowed event active.\n ");
  596.   if (NewUserDisAllowed())          sPrintf(lbyte(buf), "New Users Disallowed event active.\n ");
  597.   if (ClassActive[CL_ANYTIME_NET])
  598.     {
  599.     sPrintf(lbyte(buf), "Anytime net active for net(s) value:%08.8lX - ",AnyTimeNets);
  600.     for (i = 0; i < 32; i++)
  601.       {
  602.       if ((1l << i) & AnyTimeNets) sprintf(lbyte(buf), "%d, ", i + 1);
  603.  
  604.       };
  605.     buf[strLen(buf) - 2] = 0;
  606.     strcat(buf, ".\n ");
  607.  
  608.     }
  609.  
  610.   }
  611. /*
  612. * ForceAnytime()
  613. *
  614. * This is an interface function for forcing anytime net.
  615. */
  616. void ForceAnytime()
  617.   {
  618.   if (ClassActive[CL_ANYTIME_NET])
  619.     {
  620.     ForceNet = !ForceNet;
  621.     ScrNewUser();
  622.  
  623.     }
  624.  
  625.   }
  626. /*
  627. * ChkTwoNumbers()
  628. *
  629. * check for equality of d1 vs d2.  This is used to search a list for a
  630. * given value.
  631. */
  632. void *ChkTwoNumbers(TwoNumbers *d1, TwoNumbers *d2)
  633.   {
  634.   if (d1->first == d2->first) return &d1->second;
  635.   return NULL;
  636.  
  637.   }
  638. /*
  639. * MakeTwo()
  640. *
  641. * This creates a new record for addition to a list.
  642. */
  643. TwoNumbers *MakeTwo(int First, long Second)
  644.   {
  645.   TwoNumbers *tmp;
  646.   tmp = (TwoNumbers *) GetDynamic(sizeof *tmp);
  647.   tmp->first  = First;
  648.   tmp->second = Second;
  649.   return tmp;
  650.  
  651.   }
  652. /*
  653. * CmpTwoLong()
  654. *
  655. * This functoin compares TwoNumbers in their long parts and returns a
  656. * value suitable for use in sorting.
  657. */
  658. int CmpTwoLong(TwoNumbers *d1, TwoNumbers *d2)
  659.   {
  660.   return (d1->second < d2->second) ? -1 : 1;
  661.  
  662.   }
  663. /*
  664. * ChED()
  665. *
  666. * This function is used to search for autodoors.  If the autodoor is found
  667. * then the address to it is returned, otherwise NULL.
  668. */
  669. void *ChED(EvDoorRec *d1, EvDoorRec *d2)
  670.   {
  671.   if (strCmpU(d1->Evt->vars.EvUserName, d2->Evt->vars.EvUserName) == SAMESTRING)
  672.   return d1->Evt;
  673.   return NULL;
  674.  
  675.   }
  676. /*
  677. * ChRed()
  678. *
  679. * This function is used to search to see if a given file is on the 'redirect'
  680. * list.  Notice we check against both name and system origin.
  681. */
  682. void *ChRed(EvDoorRec *d1, EvDoorRec *d2)
  683.   {
  684.   if (strCmpU(d1->Evt->vars.Redirect.EvFilename,
  685.   d2->Evt->vars.Redirect.EvFilename) == SAMESTRING &&
  686.   strCmpU(d1->Evt->vars.Redirect.EvSystem,
  687.   d2->Evt->vars.Redirect.EvSystem) == SAMESTRING)
  688.   return d1->Evt;
  689.   return NULL;
  690.  
  691.   }
  692. /*
  693. * EatTwoNumbers()
  694. *
  695. * This function will eat a line of text from disk and make it into a record
  696. * for placement on a disk.  It's simply a space separated string.
  697. */
  698. void *EatTwoNumbers(char *line)
  699.   {
  700.   TwoNumbers *temp;
  701.   char *space;
  702.   if ((space = strchr(line, ' ')) == NULL)
  703.   return NULL;
  704.   temp = GetDynamic(sizeof *temp);
  705.   temp->first = atoi(line);
  706.   temp->second = atol(space + 1);
  707.   return temp;
  708.  
  709.   }
  710. /*
  711. * WrtTwoNumbers()
  712. *
  713. * This function is used to write the contents of a TwoNumbers structure to
  714. * disk.  This is used for saving information concerning a list while Citadel
  715. * is temporarily down.
  716. */
  717. void WrtTwoNumbers(TwoNumbers *d)
  718.   {
  719.   extern FILE *upfd;
  720.   fprintf(upfd, "%d %d\n", d->first, d->second);
  721.  
  722.   }
  723. /*
  724. * CmpED()
  725. *
  726. * This function is used to sort a list of autodoors based on when they finish.
  727. */
  728. int CmpED(EvDoorRec *d1, EvDoorRec *d2)
  729.   {
  730.   return (d1->finish < d2->finish) ? -1 : 1;
  731.  
  732.   }
  733. /*
  734. * RedirectFile()
  735. *
  736. * This function is used to discover if the given file should be redirected from
  737. * the normal file reception area to somewhere else.
  738. *
  739. * If it should be then a pointer is returned to a string representing the new
  740. * location; otherwise, NULL is returned.
  741. */
  742. char *RedirectFile(char *filename, char *systemname)
  743.   {
  744.   EvDoorRec rec;
  745.   rec.Evt = GetDynamic(sizeof (EVENT)); /* get around possible bug */
  746.   /* prepare for search */
  747.   strCpy(rec.Evt->vars.Redirect.EvFilename, filename);
  748.   strCpy(rec.Evt->vars.Redirect.EvSystem, systemname);
  749.   Cur = SearchList(&Redirected, &rec);
  750.   free(rec.Evt);
  751.   return(char *)( (Cur != NULL) ? cfg.codeBuf + Cur->vars.Redirect.EvHomeDir : NULL);
  752.  
  753.   }
  754. /***********************************************************/
  755. void ShowTW(TwoNumbers *);
  756. void ExamineEvent(EVENT *);
  757. static char *cl[] =
  758.   {
  759.   "network", "extern", "relative", "dl-time", "anytime-net",
  760.   "doors-limit", "autodoor", "chat-on", "chat-off", "redirect",
  761.   "new-users-allowed", "new-users-disallowed", "until-done"
  762.  
  763.   };
  764. static char *ty[] =
  765.   {
  766.   "preempt", "non-preempt", "quiet"
  767.  
  768.   };
  769. static char *dy[] =
  770.   {
  771.   "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
  772.  
  773.   };
  774. void EventShow()
  775.   {
  776.   int i;
  777.   mPrintf("\nCurAbs=%ld\n ", CurAbsolute());
  778.   mPrintf("ANYTIME NET is %d\n ", ClassActive[CL_ANYTIME_NET]);
  779.   mPrintf("non-preempt nextabs is %ld, %ld seconds away\n ",
  780.   Types[2].NextAbs, Types[2].NextAbs - CurAbsolute());
  781.   mPrintf("Preemptive list (%ld):\n ", Types[0].NextAbs);
  782.   RunList(&Types[0].List, ExamineEvent);
  783.   modIn();
  784.   mPrintf("Non-Preemptive list (%ld):\n ", Types[1].NextAbs);
  785.   RunList(&Types[1].List, ExamineEvent);
  786.   modIn();
  787.   mPrintf("Quiet list (%ld):\n ", Types[2].NextAbs);
  788.   RunList(&Types[2].List, ExamineEvent);
  789.   modIn();
  790.   mPrintf("Event ending list:\n ");
  791.   RunList(&EventEnds, ShowTW);
  792.   mPrintf("Anytime net is %s\n ", (ClassActive[CL_ANYTIME_NET]) ? "On" : "Off");
  793.   if (ClassActive[CL_ANYTIME_NET])
  794.     {
  795.     msgBuf.mbtext[0] = 0;
  796.     for (i = 0; i < 32; i++)
  797.     if ((1l << i) & AnyTimeNets)
  798.     sprintf(lbyte(msgBuf.mbtext), "%d, ", i + 1);
  799.     if (strlen(msgBuf.mbtext))
  800.     msgBuf.mbtext[strLen(msgBuf.mbtext) - 2] = 0;
  801.     mPrintf("Anytime nets: %s\n ", msgBuf.mbtext);
  802.  
  803.     }
  804.  
  805.   }
  806. void ShowTW(tw)
  807. TwoNumbers *tw;
  808.   {
  809.   mPrintf("Class %s active, shuts down @%ld\n ", cl[tw->first],
  810.   tw->second);
  811.  
  812.   }
  813. void ExamineEvent(ev)
  814. EVENT *ev;
  815.   {
  816.   int temp;
  817.   mPrintf("%s %s ", cl[ev->EvClass], ty[ev->EvType]);
  818.   mPrintf("%s ", dy[ev->EvMinutes / 1440]);
  819.   temp = ev->EvMinutes % 1440;
  820.   mPrintf("%d:%02d %d %lx\n ", temp/60, temp%60, ev->EvDur,
  821.   ev->EvExitVal);
  822.  
  823.   }
  824.